package com.firstpro.dao;


import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.util.Assert;
import org.hibernate.query.Query;
/**
 * Created by zhl on 2017/4/26.
 */

@Transactional
public class BaseDao<T> extends HibernateDaoSupport{
    private Class <T> entityClass;

    /**
     * BaseDao()的精华全在这句：(Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
     实际上，这句话咋看起来很难看的明白，理解起来就更加的吃力了，下面容我来将这句复杂的代码拆分开来，理解起来可能会好些：

     //代码块,也可将其放置到构造子中
     {
     //entityClass =(Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
     try {
     Class<?> clazz = getClass(); //获取实际运行的类的 Class
     Type type = clazz.getGenericSuperclass(); //获取实际运行的类的直接超类的泛型类型
     if(type instanceof ParameterizedType){ //如果该泛型类型是参数化类型
     Type[] parameterizedType = ((ParameterizedType)type).getActualTypeArguments();//获取泛型类型的实际类型参数集
     entityClass = (Class<T>) parameterizedType[0]; //取出第一个(下标为0)参数的值
     }
     } catch (Exception e) {
     e.printStackTrace();
     }

     }
     */
    public BaseDao(){
        Type type = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType)type).getActualTypeArguments();
        entityClass = (Class)params[0];
    }
    /**
     * 继承hibernateDAOSupport（抽象类，所有方法为final），必须注入SessionFactory或HibernateTemplate，
     * 可以使用@Repository为hibernateDAOSupport注入。
     */
    @Resource(name = "sessionFactory")
    private void setSuperSessionFactory(SessionFactory sessionFactory){
        super.setSessionFactory(sessionFactory);
    }
    /**
     * 立即加载
     * */
    public T get(Long id) {
        return (T) getHibernateTemplate().get(entityClass, id);
    }

    /**
     * 延迟加载
     * */
    public T load(Long id) {
        return (T) getHibernateTemplate().load(entityClass, id);
    }

    /**
     * （延迟）加载所有实体*/
    public List<T> getAll() {
        return getHibernateTemplate().loadAll(entityClass);
    }

    /**
     * 删除
     * */
    public void delete(T entity) {
        getHibernateTemplate().delete(entity);
    }

    /**
     * 更新
     * */
    public void update(T entity) {
        getHibernateTemplate().update(entity);
    }

    /**
     * 保存
     * */
    public void save(T entity){
        //System.out.println("Hibernate-inner"+hibernateTemplate);
        getHibernateTemplate().save(entity);
    }

    /**
     * 保存或更新
     * */
    public void saveOrUpdate(T entity){
        getHibernateTemplate().saveOrUpdate(entity);
    }

    /**
     * 查询
     * */
    public List<?> find(String hql, Object...params){
        return getHibernateTemplate().find(hql, params);
    }
    /**
     * 分页支持的查询
     */
    public Page pageQuery(Long page, Long numPerPage, String hql, Object... params){
        Assert.hasText(hql,"查询语句为空");
        Assert.isTrue(page>0, "页码范围应该大于0");

        String queryString = "select count(*)" + removeSelect(removeOrder(hql));
        List resultSet = getHibernateTemplate().find(queryString);
        Long totle = (Long) resultSet.get(0);
        Query query = creatQuery(hql,params);
        int start = (int)(page * numPerPage - 1);
        List list = query.setFirstResult(start).setMaxResults(numPerPage.intValue()).list();
        Long nbstar = Long.valueOf(start);
        return  new Page(list,totle,numPerPage,nbstar);

    }
    /**
     * 生成填装了属性的query
     */
    private Query creatQuery(String hql, Object... params){
        Assert.hasText(hql,"查询语句非法");
        Query query = currentSession().createQuery(hql);
        for (int lenth = 0; lenth < params.length; lenth++){
            query.setParameter(lenth,params[lenth]);
        }
        return query;
    }
    /**
     * 供分页查询方法标准化hql所用,没看懂
     * @param hql
     * @return
     */
    private static String removeOrder(String hql) {
       Assert.hasText(hql,"查询语句为空");
        Pattern pattern = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*",Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(hql);
        StringBuffer stringBuffer = new StringBuffer();
        while (matcher.find()){
            matcher.appendReplacement(stringBuffer,"");
        }
        matcher.appendTail(stringBuffer);
        return stringBuffer.toString();
    }

    /**
     * 供分页查询方法标准化hql所用
     * @param hql
     * @return
     */
    private static String removeSelect(String hql){
        Assert.hasText(hql,"hql为空");
        int startnum = hql.toLowerCase().indexOf("from");
        Assert.isTrue(startnum != -1,"hql不合法,没有from关键字");
        return hql.substring(startnum);
    }
}
